package ch.jamme.impl;

import java.util.concurrent.*;

import org.jdom.*;

import ch.jamme.reference.*;

class ObjectToXmlProducer extends ObjectToXmlConvertor {

	private int parallelThreadsNumber;

	private ExecutorService executorService;
	private BlockingQueue<XmlMarshallableReference> queue = new LinkedBlockingQueue<XmlMarshallableReference>();

	ObjectToXmlProducer(MarshallerEngine marshallerEngine, int parallelThreadsNumber) {
		super(marshallerEngine);
		this.parallelThreadsNumber = parallelThreadsNumber;
		executorService = Executors.newFixedThreadPool(parallelThreadsNumber);
	}

	@Override
	protected Element toElement(Object object) {
		// create and start the consumer threads
		ObjectToXmlConsumer consumer = new ObjectToXmlConsumer(marshallerEngine, queue);
		for (int i = 0; i < parallelThreadsNumber; i++) executorService.execute(consumer);

		Element rootElement = new Element(namingConvention.getRootTag(object));
		if (configuration.getMarshallStyle().printObjectIds())
			rootElement.setAttribute(namingConvention.getIdentifierAttribute(), "1");
		
		super.populateElement(rootElement, object);
		
		try {
			// put as many poison pills on the queue as the number of the consumer threads to signal them that their work is finished
			for (int i = 0; i < parallelThreadsNumber; i++) queue.put(XmlMarshallableReference.createVoidReference());
			
			// wait until all the consumer threads have finished
			executorService.shutdown();
			executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
		if (consumer.getFailureException() != null) throw consumer.getFailureException();
		
		return rootElement;
	}

	@Override
	protected void populateElement(Element element, Object object) {
		try {
			queue.put(new XmlMarshallableReference(element, object));
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
}
